package com.zhaopin.netty.tianyuan;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Created by TianYuan on 2018/1/5.
 */
public class NetIO {

    private static Logger logger = LoggerFactory.getLogger(NetIO.class);

    protected int bindPort;
    protected EventLoopGroup bossGroup ;
    protected EventLoopGroup workerGroup;
    protected ServerBootstrap bootStrap;
    protected ChannelInitializer<Channel> initializer;

    public NetIO(int port,ChannelInitializer<Channel> initializer){
        this.bindPort = port;
        this.initializer = initializer;
    }

    public NetIO init(){
        String os = System.getProperty("os.name");
        if(os.toLowerCase().startsWith("win") || os.toLowerCase().startsWith("mac")){
            bossGroup = new NioEventLoopGroup(1);
            workerGroup = new NioEventLoopGroup(4);
        }else{
            bossGroup = new EpollEventLoopGroup(1);
            workerGroup = new EpollEventLoopGroup(4);
        }
        bootStrap = new ServerBootstrap();
        bootStrap.group(bossGroup,workerGroup);
        if(os.toLowerCase().startsWith("win") || os.toLowerCase().startsWith("mac")) {
            bootStrap.channel(NioServerSocketChannel.class);
        }else{
            bootStrap.channel(EpollServerSocketChannel.class);
        }
        bootStrap.childHandler(initializer);
        bootStrap.childOption(ChannelOption.SO_KEEPALIVE, true);
        bootStrap.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
        bootStrap.option(ChannelOption.TCP_NODELAY, true);
        bootStrap.option(ChannelOption.SO_LINGER, 0);
        bootStrap.option(ChannelOption.SO_REUSEADDR, true);
        bootStrap.option(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, 48 * 1024);
        bootStrap.option(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 96 * 1024);
        bootStrap.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
        bootStrap.option(ChannelOption.SO_RCVBUF, 128*1024);
        bootStrap.option(ChannelOption.SO_SNDBUF, 256*1024);
        return this;
    }

    public <T> NetIO option(ChannelOption<T> option,T value){
        bootStrap.option(option, value);
        return this;
    }

    public void bind(){
        bootStrap.bind(bindPort).syncUninterruptibly();
        logger.info("start listening port:"+bindPort);
    }

    public void shutdown(){
        workerGroup.shutdownGracefully();
        bossGroup.shutdownGracefully();
        logger.info("shutdown net port");
    }
}
